/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

import { Heap } from '../../../../common/util/heap.js';
import { TaskState } from '../enum/task-state.js';
import { Work } from '../model/work.js';
import { TcbStore } from '../store/tcb-store.js';

import { ReadyQueue } from './ready-queue.js';

/**
 * 按worker分组的优先就绪队列
 *
 * @since 2022/8/24
 */
export class ClusterPriorityReadyQueue implements ReadyQueue {
  private heaps: Map<number, Heap<Work>>;

  constructor(num: number) {
    this.heaps = new Map();
    for (let i = 0; i < Math.floor(num); i++) {
      this.heaps.set(
        i,
        new Heap(function (a: Work, b: Work) {
          return a.getPriority() - b.getPriority();
        }),
      );
    }
  }

  clear(): void {
    this.heaps.forEach((heap) => heap.clear());
  }

  empty(): boolean {
    for (let i = 0; i < this.heaps.size; i++) {
      if (!this.heaps.get(i)!.empty()) {
        return false;
      }
    }
    return true;
  }

  pop(): Work | undefined {
    for (let i = 0; i < this.heaps.size; i++) {
      const heap: Heap<Work> = this.heaps.get(i)!;
      if (!heap.empty()) {
        return heap.pop();
      }
    }
    return undefined;
  }

  push(work: Work): void {
    const targetWorkers: number[] | undefined = work.getTargetWorkers();
    if (targetWorkers) {
      for (const worker of targetWorkers) {
        this.heaps.get(worker)?.push(work);
      }
    } else {
      for (let i = 0; i < this.heaps.size; i++) {
        this.heaps.get(i)?.push(work);
      }
    }
  }

  update(work: Work): void {
    for (let i = 0; i < this.heaps.size; i++) {
      const heap: Heap<Work> = this.heaps.get(i)!;
      heap.update(work);
    }
  }

  /**
   * 获取一个worker对应的工作单元堆
   *
   * @param workerId worker的id
   * @returns {Heap<Work> | undefined} 对应的工作单元堆
   */
  getWorkHeap(workerId: number): Heap<Work> | undefined {
    return this.heaps.get(workerId);
  }

  /**
   * 获取第一个尚未执行的工作单元
   *
   * @param workerId worker的id
   * @returns {Work | undefined} 第一个尚未执行的工作单元
   */
  getFirstWaitingWork(workerId: number): Work | undefined {
    const heap: Heap<Work> | undefined = this.getWorkHeap(workerId);
    if (!heap) {
      return undefined;
    }
    while (!heap.empty()) {
      const work: Work = heap.pop()!;
      if (TcbStore.getTCB(work.getId())?.getState() === TaskState.WAITING) {
        return work;
      }
    }
    return undefined;
  }

  pushWork(work: Work, workerId: number): void {
    this.heaps.get(workerId)?.push(work);
  }
}
